home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / browser.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  16KB  |  652 lines

  1. /*
  2.  * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
  3.  * 
  4.  *     This program is free software; you can redistribute it and/or modify
  5.  *     it under the terms of the GNU General Public License as published by
  6.  *     the Free Software Foundation; either version 2 of the License, or
  7.  *     (at your option) any later version.
  8.  * 
  9.  *     This program is distributed in the hope that it will be useful,
  10.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *     GNU General Public License for more details.
  13.  * 
  14.  *     You should have received a copy of the GNU General Public License
  15.  *     along with this program; if not, write to the Free Software
  16.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */ 
  18.  
  19. #include "mutt.h"
  20. #include "mutt_curses.h"
  21. #include "mutt_menu.h"
  22. #include "buffy.h"
  23. #include "sort.h"
  24. #include "mailbox.h"
  25.  
  26. #include <stdlib.h>
  27. #include <dirent.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <sys/stat.h>
  31. #include <pwd.h>
  32. #include <grp.h>
  33.  
  34. /* HP-UX and ConvexOS don't have this macro */
  35. #ifndef S_ISLNK
  36. #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK ? 1 : 0)
  37. #endif
  38.  
  39. struct folder_file
  40. {
  41.   mode_t mode;
  42.   time_t mtime;
  43.   off_t size;
  44.   char *name;
  45.   char *desc;
  46. };
  47.  
  48. struct browser_state
  49. {
  50.   struct folder_file *entry;
  51.   short entrylen; /* number of real entries */
  52.   short entrymax;  /* max entry */
  53. };
  54. static char LastDir[_POSIX_PATH_MAX] = "";
  55.  
  56. /* Frees up the memory allocated for the local-global variables.  */
  57. static void destroy_state (struct browser_state *state)
  58. {
  59.   int c;
  60.  
  61.   for (c = 0; c < state->entrylen; c++)
  62.   {
  63.     safe_free ((void **) &((state->entry)[c].name));
  64.     safe_free ((void **) &((state->entry)[c].desc));
  65.   }
  66.   safe_free ((void **) &state->entry);
  67. }
  68.  
  69. static int browser_compare_subject (const void *a, const void *b)
  70. {
  71.   struct folder_file *pa = (struct folder_file *) a;
  72.   struct folder_file *pb = (struct folder_file *) b;
  73.  
  74.   int r = strcmp (pa->name, pb->name);
  75.  
  76.   return ((BrowserSort & SORT_REVERSE) ? -r : r);
  77. }
  78.  
  79. static int browser_compare_date (const void *a, const void *b)
  80. {
  81.   struct folder_file *pa = (struct folder_file *) a;
  82.   struct folder_file *pb = (struct folder_file *) b;
  83.  
  84.   int r = pa->mtime - pb->mtime;
  85.  
  86.   return ((BrowserSort & SORT_REVERSE) ? -r : r);
  87. }
  88.  
  89. static int browser_compare_size (const void *a, const void *b)
  90. {
  91.   struct folder_file *pa = (struct folder_file *) a;
  92.   struct folder_file *pb = (struct folder_file *) b;
  93.  
  94.   int r = pa->size - pb->size;
  95.  
  96.   return ((BrowserSort & SORT_REVERSE) ? -r : r);
  97. }
  98.  
  99. static void browser_sort (struct browser_state *state)
  100. {
  101.   int (*f) (const void *, const void *);
  102.  
  103.   switch (BrowserSort & SORT_MASK)
  104.   {
  105.     case SORT_ORDER:
  106.       return;
  107.     case SORT_DATE:
  108.       f = browser_compare_date;
  109.       break;
  110.     case SORT_SIZE:
  111.       f = browser_compare_size;
  112.       break;
  113.     case SORT_SUBJECT:
  114.     default:
  115.       f = browser_compare_subject;
  116.       break;
  117.   }
  118.   qsort (state->entry, state->entrylen, sizeof (struct folder_file), f);
  119. }
  120.  
  121. static int link_is_dir (const char *path)
  122. {
  123.   struct stat st;
  124.  
  125.   if (stat (path, &st) == 0)
  126.     return (S_ISDIR (st.st_mode));
  127.   else
  128.     return (-1);
  129. }
  130.  
  131. static void add_folder (MUTTMENU *m, struct browser_state *state,
  132.             const char *name, const struct stat *s, int new)
  133. {
  134.   char buffer[_POSIX_PATH_MAX + SHORT_STRING];
  135.   struct passwd *pw;
  136.   struct group *gr;
  137.   char date[16];
  138.   char *fmt;
  139.   time_t tnow;
  140.  
  141.   pw = getpwuid (s->st_uid);
  142.   gr = getgrgid (s->st_gid);
  143.   
  144.   tnow = time (NULL);
  145.   fmt = tnow - s->st_mtime < 31536000 ? "%b %d %H:%M" : "%b %d  %Y";
  146.   strftime (date, sizeof (date), fmt, localtime (&s->st_mtime));
  147.   
  148.   snprintf (buffer, sizeof (buffer), "%c %c%c%c%c%c%c%c%c%c%c %2d %-8.8s %-8.8s %8ld %s %s%s",
  149.          new ? 'N' : ' ',
  150.          S_ISDIR(s->st_mode) ? 'd' : (S_ISLNK(s->st_mode) ? 'l' : '-'),
  151.          
  152.          (s->st_mode & S_IRUSR) != 0 ? 'r': '-',
  153.          (s->st_mode & S_IWUSR) != 0 ? 'w' : '-',
  154.          (s->st_mode & S_ISUID) != 0 ? 's' : (s->st_mode & S_IXUSR) != 0 ? 'x': '-',
  155.          
  156.          (s->st_mode & S_IRGRP) != 0 ? 'r' : '-',
  157.          (s->st_mode & S_IWGRP) != 0 ? 'w' : '-',
  158.          (s->st_mode & S_ISGID) != 0 ? 's' : (s->st_mode & S_IXGRP) != 0 ? 'x': '-',
  159.          
  160.          (s->st_mode & S_IROTH) != 0 ? 'r' : '-',
  161.          (s->st_mode & S_IWOTH) != 0 ? 'w' : '-',
  162.          (s->st_mode & S_ISVTX) != 0 ? 't' : (s->st_mode & S_IXOTH) != 0 ? 'x': '-',
  163.          s->st_nlink,
  164.          pw ? pw->pw_name : "(null)",
  165.          gr ? gr->gr_name : "(null)",
  166.          (long) s->st_size,
  167.          date,
  168.          name,
  169.          S_ISLNK (s->st_mode) ? "@" : (S_ISDIR (s->st_mode) ? "/" : ((s->st_mode & S_IXUSR) != 0 ? "*" : "")));
  170.   
  171.   if (state->entrylen == state->entrymax)
  172.   {
  173.     /* need to allocate more space */
  174.     safe_realloc ((void **) &state->entry,
  175.           sizeof (struct folder_file) * (state->entrymax += 256));
  176.     if (m)
  177.       m->data = state->entry;
  178.   }
  179.  
  180.   (state->entry)[state->entrylen].mode = s->st_mode;
  181.   (state->entry)[state->entrylen].mtime = s->st_mtime;
  182.   (state->entry)[state->entrylen].size = s->st_size;
  183.   (state->entry)[state->entrylen].name = safe_strdup (name);
  184.   (state->entry)[state->entrylen].desc = safe_strdup (buffer);
  185.  
  186.   (state->entrylen)++;
  187. }
  188.  
  189. static void init_state (struct browser_state *state, MUTTMENU *menu)
  190. {
  191.   state->entrylen = 0;
  192.   state->entrymax = 256;
  193.   state->entry = (struct folder_file *) safe_malloc (sizeof (struct folder_file) * state->entrymax);
  194.   if (menu)
  195.     menu->data = state->entry;
  196. }
  197.  
  198. static int examine_directory (MUTTMENU *menu, struct browser_state *state,
  199.                   const char *d, const char *prefix)
  200. {
  201.   struct stat s;
  202.   DIR *dp;
  203.   struct dirent *de;
  204.   char buffer[_POSIX_PATH_MAX + SHORT_STRING];
  205.   BUFFY *tmp;
  206.  
  207.   if (stat (d, &s) == -1)
  208.   {
  209.     mutt_perror (d);
  210.     return (-1);
  211.   }
  212.  
  213.   if (!S_ISDIR (s.st_mode))
  214.   {
  215.     mutt_error ("%s is not a directory", d);
  216.     return (-1);
  217.   }
  218.  
  219.   mutt_buffy_check ();
  220.  
  221.   if ((dp = opendir (d)) == NULL)
  222.   {
  223.     mutt_perror (d);
  224.     return (-1);
  225.   }
  226.  
  227.   init_state (state, menu);
  228.  
  229.   while ((de = readdir (dp)) != NULL)
  230.   {
  231.     if (strcmp (de->d_name, ".") == 0)
  232.       continue;    /* we don't need . */
  233.     
  234.     if (prefix && *prefix && strncmp (prefix, de->d_name, strlen (prefix)) != 0)
  235.       continue;
  236.     if (regexec (Mask.rx, de->d_name, 0, NULL, 0) != 0)
  237.       continue;
  238.  
  239.     snprintf (buffer, sizeof (buffer), "%s/%s", d, de->d_name);
  240.     if (lstat (buffer, &s) == -1)
  241.       continue;
  242.     
  243.     if ((! S_ISREG (s.st_mode)) && (! S_ISDIR (s.st_mode)) &&
  244.     (! S_ISLNK (s.st_mode)))
  245.       continue;
  246.     
  247.     tmp = Incoming;
  248.     while (tmp && strcmp (buffer, tmp->path))
  249.       tmp = tmp->next;
  250.     add_folder (menu, state, de->d_name, &s, (tmp) ? tmp->new : 0);
  251.   }
  252.   closedir (dp);  
  253.   browser_sort (state);
  254.   return 0;
  255. }
  256.  
  257. static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
  258. {
  259.   struct stat s;
  260.   char buffer[LONG_STRING];
  261.   BUFFY *tmp = Incoming;
  262.  
  263.   if (!Incoming)
  264.     return (-1);
  265.   mutt_buffy_check();
  266.  
  267.   init_state (state, menu);
  268.  
  269.   do
  270.   {
  271.     if (lstat (tmp->path, &s) == -1)
  272.       continue;
  273.  
  274.     if ((! S_ISREG (s.st_mode)) && (! S_ISDIR (s.st_mode)) &&
  275.     (! S_ISLNK (s.st_mode)))
  276.       continue;
  277.     
  278.     strfcpy (buffer, tmp->path, sizeof (buffer));
  279.     mutt_pretty_mailbox (buffer);
  280.  
  281.     add_folder (menu, state, buffer, &s, tmp->new);
  282.   }
  283.   while ((tmp = tmp->next));
  284.   browser_sort (state);
  285.   return 0;
  286. }
  287.  
  288. int select_file_search (MUTTMENU *menu, regex_t *re, int n)
  289. {
  290.   return (regexec (re, ((struct folder_file *) menu->data)[n].name, 0, NULL, 0));
  291. }
  292.  
  293. void folder_entry (char *s, size_t slen, MUTTMENU *menu, int num)
  294. {
  295.   snprintf (s, slen, "%2d %s", num + 1, ((struct folder_file *) menu->data)[num].desc);
  296. }
  297.  
  298. static void init_menu (struct browser_state *state, MUTTMENU *menu, char *title,
  299.                size_t titlelen, int buffy)
  300. {
  301.   char path[_POSIX_PATH_MAX];
  302.  
  303.   menu->current = 0;
  304.   menu->top = 0;
  305.   menu->max = state->entrylen;
  306.   if (buffy)
  307.     snprintf (title, titlelen, "Mailboxes [%d]", mutt_buffy_check ());
  308.   else
  309.   {
  310.     strfcpy (path, LastDir, sizeof (path));
  311.     mutt_pretty_mailbox (path);
  312.     snprintf (title, titlelen, "Directory [%s], File mask: %s",
  313.           path, Mask.pattern);
  314.   }
  315.   menu->redr